package com.hsteach.util;


import com.hsteach.common.exception.ServiceException;
import com.hsteach.common.utils.sign.Md5Utils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class AESUtil {
    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String ALGORITHM_MODE_FILL = "AES/ECB/PKCS5Padding";

    /**
     * AES的加密函数
     *
     * @param str 传入需要加密的字符
     * @param key 传入一个16位长度的密钥。否则报错
     * @return 执行成功返回加密结果，否则报错
     * @throws Exception 抛出一个加密异常
     */
    public static String encrypt(String str, String key) {
        if (str == null || key == null) {
            return null;
        }
        byte[] bytes;
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_FILL);
            cipher.init(Cipher.ENCRYPT_MODE,new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM));
            bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            throw new ServiceException("加密失败");
        }
        return bytesConvertHexString(bytes);
    }

    /**
     * AES的解密函数
     *
     * @param str 传入需要解密的字符
     * @param key 传入一个16位长度的密钥。否则报错
     * @return 执行成功返回加密结果，否则报错
     * @throws Exception 抛出一个解密异常
     */
    public static String decrypt(String str, String key) {
        if (str == null || key == null) {
            return null;
        }
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_FILL);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM));
            byte[] bytes = hexStringConvertBytes(str);
            bytes = cipher.doFinal(bytes);
            return new String(bytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new ServiceException("解密失败");
        }
    }

    /**
     * byte数组转换成十六进制字符串
     * <p>
     * 先对每个byte数值补码成十进制,
     * 然后在将十进制转换成对应的十六进制.
     * 如果单次转换, 十六进制只有一位时， 将在前面追加0变成两位.
     */
    private static String bytesConvertHexString(byte[] data) {
        StringBuffer result = new StringBuffer();
        String hexString;
        for (byte b : data) {
            // 补码成正十进制后转换成16进制
            hexString = Integer.toHexString(b & 255);
            result.append(hexString.length() == 1 ? "0" + hexString : hexString);
        }
        return result.toString().toUpperCase();
    }

/**
 * 十六进制字符串转换成byte数组
 * 在加密时, 十六进制数值和byte字节的对应关系 是:  2个十六进制数值对应  1个
 byte字节  (2: 1)
 * 所以byte数组的长度应该是十六进制字符串的一半, 并且在转换时
 * 应是两个十六进制数值转换成一个byte字节  (2个2个十六进制数值进行转换)
 * 这也是为什么可以*2的原因， 例如: 0, 2, 4, 6, 8, 10, 12 依次遍历
 */
private static byte[] hexStringConvertBytes(String data) {
    int length = data.length() / 2;
    byte[] result = new byte[length];
    for (int i = 0; i < length; i++) {
        int first = Integer.parseInt(data.substring(i * 2, i * 2 + 1), 16);
        int second = Integer.parseInt(data.substring(i * 2 + 1, i * 2 + 2), 16);
        result[i] = (byte) (first * 16 + second);
    }
    return result;
}
}
